# -*- coding:utf-8 -*-
"""
作者：520
日期：2023年12月08日
"""
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, BatchNormalization,Activation
from keras import utils
from keras import regularizers
import warnings

# 只显示错误级别的警告

warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置字体系列
plt.rcParams['axes.unicode_minus'] = False  # 设置坐标轴负号的显示
plt.rcParams['figure.figsize'] = (7, 7)  # 设置图形大小
nb_classes = 10  # 类别数
(X_train, y_train), (X_test, y_test) = mnist.load_data()  # 加载MNIST数据集
print("训练数据集大小：", X_train.shape, y_train.shape, "测试数据集大小：", X_test.shape, y_test.shape)  # 打印数据集大小
for i in range(9):  # 循环遍历前9个样本
    plt.subplot(3, 3, i + 1)  # 创建一个3x3的子图，并指定子图编号
    plt.imshow(X_train[i], cmap="gray")  # 显示训练集中的第i个图像，使用灰度映射
    plt.title("数字" + str(y_train[i]))  # 设置子图的标题为第i个数字的字符串形式
    plt.axis('off')  # 关闭子图的坐标轴显示
plt.show()  # 显示图像
X_train = X_train.reshape(60000, 784)  # 将训练集形状改变为60000行，784列
x_test = X_test.reshape(10000, 784)  # 将测试集形状改变为10000行，784列
X_train = X_train.astype('float32')  # 将训练集转换为浮点型
x_test = x_test.astype('float32')  # 将测试集转换为浮点型
X_train /= 255  # 将训练集除以255进行归一化
x_test /= 255  # 将测试集除以255进行归一化
y_train = utils.to_categorical(y_train, nb_classes)  # 将训练集标签转换为独热编码格式
y_test = utils.to_categorical(y_test, nb_classes)  # 将测试集标签转换为独热编码格式
print("训练数据集大小：", X_train.shape, y_train.shape, "测试数据集大小：", x_test.shape, y_test.shape)  # 打印数据集大小
model = Sequential()  # 创建一个Sequential模型
model.add(Dense(512, activation='relu', input_shape=(784,)))  # 添加一个全连接层，输出节点数为512，激活函数为relu
model.add(BatchNormalization())  # 添加批量归一化层
model.add(Dropout(0.2))  # 添加一个随机失活层，防止过拟合
model.add(Dense(512, kernel_regularizer=regularizers.l2(0.01), activation='relu'))  # 添加一个全连接层，输出节点数为512，激活函数为relu
model.add(BatchNormalization())  # 添加批量归一化层
model.add(Dropout(0.2))  # 添加一个随机失活层，防止过拟合
model.add(Dense(10, activation='softmax'))  # 添加一个全连接层，输出节点数为10，激活函数为softmax
model.summary()  # 打印模型结构概览
utils.plot_model(model)  # 绘制模型结构图
model.compile(loss=tf.keras.losses.categorical_crossentropy, optimizer=tf.keras.optimizers.Adam(), metrics=tf.keras.metrics.categorical_accuracy)  # 编译模型，指定损失函数、优化器和评估指标
history = model.fit(X_train, y_train, batch_size=128, epochs=4, verbose=1, validation_data=(x_test, y_test))  # 训练模型，并打印训练过程中的验证集损失和准确率
print(history.history)  # 打印训练历史记录
plt.figure()  # 创建一个新的图形
plt.plot(history.history['loss'], label="train")  # 在图形中绘制训练集的损失函数曲线
plt.plot(history.history["val_loss"], label="val")  # 在图形中绘制验证集的损失函数曲线
plt.legend()  # 添加图例
plt.grid()  # 添加网格线
plt.show()  # 显示图形
plt.figure()  # 创建一个新的图形
plt.plot(history.history['categorical_accuracy'], label="train")  # 在图形中绘制训练集的准确率曲线
plt.plot(history.history["val_categorical_accuracy"], label="val")  # 在图形中绘制验证集的准确率曲线
plt.legend()  # 添加图例
plt.grid()  # 添加网格线
plt.show()  # 显示图形
tensorboard = tf.keras.callbacks.TensorBoard(log_dir="./graph")  # 创建一个TensorBoard回调函数
history = model.fit(X_train, y_train, epochs=10, validation_data=(x_test, y_test), batch_size=128, verbose=1, callbacks=[tensorboard])  # 训练模型，并使用回调函数记录训练过程
print(model.evaluate(x_test, y_test, verbose=1))  # 在测试集上评估模型的性能
model.save("model.h5")  # 保存模型到文件中
